/*
 * MockProtocolHandler.java    0.0.1    19/set/2009
 * 
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */ 
package org.mentalsmash.tazio.net.cs.server.impl.mock;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicInteger;

import org.mentalsmash.tazio.net.cs.server.ProtocolHandler;
import org.mentalsmash.tazio.net.cs.server.impl.ChannelFacade;
import org.mentalsmash.tazio.net.cs.server.impl.InputQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Fake protocol hanlder. Used for unit testing.
 * @version    0.0.1    19/set/2009    
 * @author     Andrea Reale <andrea.reale@gmail.com>
 */
public class MockProtocolHandler implements ProtocolHandler {

	private final static AtomicInteger COUNT = new AtomicInteger();
	private final static Logger log = LoggerFactory.getLogger(MockProtocolHandler.class);
	private final static int STEP = 1024;
	
	private final int seqno = COUNT.incrementAndGet();
	/**
	 * The default message returned by this mock implementation
	 */
	public final static String MESSAGE = "MOCK MESSAGE!";
	
	private final String message;
	//DO THIS VARIABLES GET ACCESSED BY MULTIPLE THREADS? Not in test since I'm writing them,
	//Be sure to double check it in normal deployments
	private boolean registered;

	private AtomicInteger numMessagesHandled = new AtomicInteger();
	
	/**
	 * Create a new mock ProtocolHandler. Whichever input is read from the associated channel this protocol
	 * handler returns the message <code>MockProtocolHandler.MESSAGE</code>
	 */
	public MockProtocolHandler() {
		message = MockProtocolHandler.MESSAGE;
	}
	
	/**
	 * Create a new mock ProtocolHandler. Whichever input is read from the associated channel this protocol
	 * handler returns the message passed as argument.
	 * @param msg the message to return upon input reception
	 */
	public MockProtocolHandler(String msg) {
		message = msg;
	}
	
	/**
	 * Method used to test whether the mock protocol handler register method has been called
	 * @return true if the mock protocol handler <code>register()</code> method has been called
	 */
	public boolean isRegistered() {
		return registered;
	}



	/**
	 * Method used to test whether the mock protocol handler unregister method has been called
	 * @return true if the mock protocol handler <code>unregister()</code> method has been called
	 */
	public boolean isUnregistered() {
		return !registered;
	}



	/**
	 * @return the numMessagesHandled
	 */
	public int getNumMessagesHandled() {
		return numMessagesHandled.intValue();
	}


	
	/**
	 * This mock implementation simply increments an internal counter whose value can be 
	 * fetched calling {@link org.mentalsmash.tazio.net.cs.server.impl.mock.MockProtocolHandler#getNumMessagesHandled getNumMessageHandled()}.
	 * Morover it puts on the output queue of the source of the message the message
	 * {@link MockProtocolHandler#MESSAGE MESSAGE}
	 */
	@Override
	public void handleMessage(ByteBuffer message, ChannelFacade source) {
		numMessagesHandled.incrementAndGet();
		log.debug("New Message Handled");
		source.getOutputQueue().enqueue(message); //Throw MESSAGE in the output

	}

	/* (non-Javadoc)
	 * @see org.mentalsmash.tazio.net.cs.server.ProtocolHandler#nextMessage(org.mentalsmash.tazio.net.cs.server.ChannelFacade)
	 */
	/**
	 * This mock implementation returns null if the input queue associated to the source is empty.
	 * Otherwise it drains the input completely and returns a ByteBuffer containing a default message, encoded
	 * using the system's default charset.
	 * 
	 * @return the contents of {@link MockProtocolHandler#MESSAGE MESSAGE} encoded with the system's
	 *         default charset
	 */
	@Override
	public ByteBuffer nextMessage(ChannelFacade source) {
		InputQueue input = source.getInputQueue();
		if(input.isEmpty()) {
			log.debug("Received an empty input");
			return null;
		}
		
		while(!input.isEmpty()){
			input.dequeueBytes(MockProtocolHandler.STEP); //empty the input channel
		}
		
		byte[] msg = message.getBytes(Charset.defaultCharset());
		ByteBuffer protocolMessage = ByteBuffer.wrap(msg);
		
		return protocolMessage;		
	}

	/* (non-Javadoc)
	 * @see org.mentalsmash.tazio.net.cs.server.ProtocolHandler#registered(org.mentalsmash.tazio.net.cs.server.ChannelFacade)
	 */
	@Override
	public synchronized void registered(ChannelFacade source) {
		if(!registered) {
			registered = true;
		}

	}

	/* (non-Javadoc)
	 * @see org.mentalsmash.tazio.net.cs.server.ProtocolHandler#unregistered(org.mentalsmash.tazio.net.cs.server.ChannelFacade)
	 */
	@Override
	public synchronized void unregistered(ChannelFacade source) {
		if(registered){
			registered = false;
		}

	}
	
	@Override
	public String toString() {
		return "Mock-" + seqno;
	}

}
